#include <gtest/gtest.h>
#include <iostream>
#include "Variable.h"
#include "Data.h"
#include "Expression.h"
#include "Memory.h"

TEST(ExpressionTest, BasicUsage) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::BOOLEAN, &memory);
	Variable* yesOrNo = Variable::createVariable("yesOrNo", Data::createBoolean(true));
	e->addSubExpression(yesOrNo);
	EXPECT_EQ(e->getBooleanValue(), true);
}

TEST(ExpressionTest, ConvinienceMethods) {
	
	Memory memory;
	
	Expression* e1 = Expression::createSingleBoolean(true, &memory);
	EXPECT_EQ(e1->getBooleanValue(), true);
	
	Expression* e2 = Expression::createSingleFloat(3.5f, &memory);
	EXPECT_FLOAT_EQ(e2->getFloatValue(), 3.5f);
	
	Expression* e3 = Expression::createSingleInt(33, &memory);
	EXPECT_EQ(e3->getIntValue(), 33);
	
	Expression* e4 = Expression::createSingleString("Hej!", &memory);
	EXPECT_EQ(e4->getStringValue(), "Hej!");
	
	Expression* e5 = Expression::createSingleVariableName("x", &memory);
	EXPECT_EQ(e5->getVariableName(), "x");
}

TEST(ExpressionTest, AddingInts) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::INT, &memory);
	e->addSubExpression(Data::createInt(20));
	e->addSubExpression(Data::createInt(30));
	EXPECT_EQ(e->getIntValue(), 50);
}

TEST(ExpressionTest, AddingFloats) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::FLOAT, &memory);
	e->addSubExpression(Data::createFloat(12.5f));
	e->addSubExpression(Data::createFloat(3.5f));
	EXPECT_FLOAT_EQ(e->getFloatValue(), 16.0f);
}

TEST(ExpressionTest, AddingBools) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::BOOLEAN, &memory);
	e->addSubExpression(Data::createBoolean(true));
	e->addSubExpression(Data::createBoolean(false));
	EXPECT_EQ(e->getBooleanValue(), true);
}

TEST(ExpressionTest, AddingStrings) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::STRING, &memory);
	e->addSubExpression(Data::createString("Hello"));
	e->addSubExpression(Data::createString("World"));
	EXPECT_EQ(e->getStringValue(), "HelloWorld");
}

TEST(ExpressionTest, MultiplyingInts) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::INT, &memory, Expression::MULTIPLY);
	e->addSubExpression(Data::createInt(3));
	e->addSubExpression(Data::createInt(6));
	EXPECT_EQ(e->getIntValue(), 18);
}

TEST(ExpressionTest, MultiplyingFloats) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::FLOAT, &memory, Expression::MULTIPLY);
	e->addSubExpression(Data::createFloat(2.5f));
	e->addSubExpression(Data::createFloat(3.25f));
	EXPECT_EQ(e->getFloatValue(), 8.125f);
}

TEST(ExpressionTest, MultiplyingBooleans1) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::BOOLEAN, &memory, Expression::MULTIPLY);
	e->addSubExpression(Data::createBoolean(true));
	e->addSubExpression(Data::createBoolean(false));
	EXPECT_EQ(e->getBooleanValue(), false);
}

TEST(ExpressionTest, MultiplyingBooleans2) {
	Memory memory;
	Expression* e = Expression::createExpression(DataHolder::BOOLEAN, &memory, Expression::MULTIPLY);
	e->addSubExpression(Data::createBoolean(true));
	e->addSubExpression(Data::createBoolean(true));
	EXPECT_EQ(e->getBooleanValue(), true);
}

TEST(ExpressionTest, VariableExpression) {
	
	Memory memory;

	Variable* v1 = Variable::createVariable("v1", Data::createInt(5));
	Variable* v2 = Variable::createVariable("v2", Data::createInt(4));
	
	{
		Expression* e = Expression::createExpression(DataHolder::INT, &memory, Expression::ADD);
		e->addSubExpression(v1);
		e->addSubExpression(v2);
		
		EXPECT_EQ(e->getIntValue(), 9);	
	}
	
}
	 
TEST(ExpressionTest, SubExpressionsWithIntegers) {

	Memory memory;
	
	Expression* e1 = Expression::createExpression(DataHolder::INT, &memory, Expression::ADD);
	e1->addSubExpression(Data::createInt(3));
	
	Expression* e2 = Expression::createExpression(DataHolder::INT, &memory, Expression::ADD);
	e2->addSubExpression(Data::createInt(7));
	
	Expression* e3 = Expression::createExpression(DataHolder::INT, &memory, Expression::ADD);
	e3->addSubExpression(e1);
	e3->addSubExpression(e2);
	
	EXPECT_EQ(e3->getIntValue(), 10);
}


TEST(ExpressionTest, MultiplyTwoFloatValuesStoredInVariables) {

	Memory memory;
	
	memory.addVariable(Variable::createVariable("a", Data::createFloat(4.5f)));
	memory.addVariable(Variable::createVariable("b", Data::createFloat(2.0f)));
	
	Expression* e = Expression::createExpression(DataHolder::FLOAT, &memory, Expression::MULTIPLY);
	e->addSubExpression(Data::createVariableName("a"));
	e->addSubExpression(Data::createVariableName("b"));
	
	EXPECT_FLOAT_EQ(e->getFloatValue(), 9.0f);
	
}

TEST(ExpressionTest, CombineTwoStringsThatAreStoredInVariables) {
	
	Memory memory;
	
	memory.addVariable(Variable::createVariable("firstHalf", Data::createString("Hello")));
	memory.addVariable(Variable::createVariable("secondHalf", Data::createString("String")));
	
	Expression* e = Expression::createExpression(DataHolder::STRING, &memory, Expression::ADD);
	e->addSubExpression(Data::createVariableName("firstHalf"));
	e->addSubExpression(Data::createVariableName("secondHalf"));
	
	EXPECT_EQ(e->getStringValue(), "HelloString");
	
}

TEST(ExpressionTest, BooleanVariableMultipliedWithAnotherBool) {
	
	Memory memory;
	
	memory.addVariable(Variable::createVariable("p", Data::createBoolean(true)));
	
	Expression* e = Expression::createExpression(DataHolder::BOOLEAN, &memory, Expression::MULTIPLY);
	e->addSubExpression(Data::createVariableName("p"));
	e->addSubExpression(Data::createBoolean(false));
	
	EXPECT_EQ(e->getBooleanValue(), false);
}

TEST(ExpressionTest, VariableReferencingAnotherVariableThatIsContainingAnInt) {
	
	Memory memory;
	
	memory.addVariable(Variable::createVariable("age", Data::createInt(18)));
	memory.addVariable(Variable::createVariable("reference", Data::createVariableName("age")));
	
	Expression* e = Expression::createExpression(DataHolder::INT, &memory);
	e->addSubExpression(Data::createVariableName("reference"));
	
	EXPECT_EQ(e->getIntValue(), 18);
}

